﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using Microsoft.PointOfService;
using Microsoft.PointOfService.BaseServiceObjects;


namespace CA.RetailBeerSystems.POSServiceObjects.Scanners
{
	[HardwareId("HID\\Vid_0536&Pid_0107", "HID\\Vid_0536&Pid_FFF"),
		//[HardwareId(@"HID\Vid_0536&Pid_0107&Rev_0000", @"HID\Vid_0536&Pid_FFF&Rev_9999"), 
	ServiceObject(DeviceType.Scanner, "HHPScannerSO", "Service Object for Hand Held Products Scanner", 1, 11)]
	public class HandHeldScanner : ScannerBase
	{

		#region Fields

		// Fields
		private bool autodisable;
		private string checkhealthtext = "OK";
		private const int HANDHELD_VID = 0x218;
		private byte[] hhAimID;
		private byte hhCodeID;
		private byte[] hhScanData;
		private int hhScanDataLen;
		private IntPtr HidHandle = IntPtr.Zero;
		private UsbReadThread ReadThread;
		private Hashtable scannerHash = new Hashtable();

		#endregion

		#region Constructors / Finalisers

		// Methods
		public HandHeldScanner()
		{
			this.initScannerHash();
			this.hhAimID = new byte[3];
			this.hhScanData = new byte[0x7fff];
			base.Properties.DeviceDescription = "HandHeld Scanner";

		}  // END: public HandHeldScanner()

		~HandHeldScanner()
		{
			this.Dispose(false);
		}  // END: ~HandHeldScanner()

		#endregion

		#region Overrides

		public override string CheckHealth(HealthCheckLevel level)
		{
			base.VerifyState(true, true);

			string str = "Ok";
			this.checkhealthtext = str;
			return str;

		}  // END: public override string CheckHealth(HealthCheckLevel level)

		protected override byte[] DecodeScanDataLabel(byte[] scanData)
		{
			int count = scanData[1];
			byte num2 = 0x5d;
			int sourceIndex = Array.IndexOf(scanData, num2, 0, count) + 3;
			byte[] destinationArray = new byte[count];
			Array.Copy(scanData, sourceIndex, destinationArray, 0, count);
			return destinationArray;

		}  // END: protected override byte[] DecodeScanDataLabel(byte[] scanData)

		protected override BarCodeSymbology DecodeScanDataType(byte[] scanData)
		{
			return this.GetSymbology(scanData);

		}  // END: protected override BarCodeSymbology DecodeScanDataType(byte[] scanData)

		public override DirectIOData DirectIO(int command, int data, object obj)
		{
			base.VerifyState(false, false);

			DirectIOData data2 = new DirectIOData(data, obj);
			if (this.HidHandle != IntPtr.Zero)
			{
				switch (command)
				{
					case 0:
					case 1:
						return data2;
				}
			}
			return data2;

		}  // END: public override DirectIOData DirectIO(int command, int data, object obj)

		protected override void Dispose(bool disposing)
		{
			try
			{
				if (disposing && (this.ReadThread != null))
				{
					this.ReadThread.Dispose();
					this.ReadThread = null;
				}
			}
			finally
			{
				base.Dispose(disposing);
			}

		}  // END: protected override void Dispose(bool disposing)

		public override void Open()
		{
			base.Open();

			this.ReadThread = new UsbReadThread(this);

		}  // END: public override void Open()

		internal void OnDataScanned(byte[] data)
		{
			if (data.Length < 5)
			{
				base.FailedScan();
			}
			else
			{
				int num = data[1];
				if ((num == 0) || (data.Length < (5 + num)))
				{
					base.FailedScan();
				}
				else
				{
					this.AppendHHScanData(data);
					int num2 = data[0x3f];
					if (num2 < 1)
					{
						base.GoodScan(this.GetHHScanData());
						this.ResetHHDataItems();
					}
				}
			}
			if (this.AutoDisable)
			{
				this.DeviceEnabled = false;
			}

		}  // END: internal void OnDataScanned(byte[] data)

		// Properties
		public override bool AutoDisable
		{
			get
			{
				base.VerifyState(false, false);

				return this.autodisable;
			}
			set
			{
				this.autodisable = value;
				base.AutoDisable = value;
			}

		}  // END: public override bool AutoDisable

		public override string CheckHealthText
		{
			get
			{
				base.VerifyState(false, false);

				return this.checkhealthtext;

			}

		}  // END: public override string CheckHealthText

		public override bool DeviceEnabled
		{
			get
			{
				return base.DeviceEnabled;
			}
			[System.Security.Permissions.SecurityPermission(System.Security.Permissions.SecurityAction.Demand, Flags = System.Security.Permissions.SecurityPermissionFlag.UnmanagedCode)]
			set
			{
				if (value != base.DeviceEnabled)
				{
					base.DeviceEnabled = value;
					if (!value)
					{
						this.ReadThread.CloseScanner();
					}
					else
					{
						try
						{
							this.ReadThread.OpenScanner(base.DevicePath);
							this.SetDeviceStatistics();
						}
						catch (Exception exception)
						{
							base.DeviceEnabled = false;
							if (exception is PosControlException)
							{
								throw;
							}
						}
					}
				}
			}

		}  // END: public override bool DeviceEnabled

		#endregion

		#region Private Methods

		private void AppendHHScanData(byte[] scanData)
		{
			int length = scanData[1];
			this.hhAimID[0] = scanData[2];
			this.hhAimID[1] = scanData[3];
			this.hhAimID[2] = scanData[4];
			this.hhCodeID = scanData[0x3d];
			Array.Copy(scanData, 5, this.hhScanData, this.hhScanDataLen, length);
			this.hhScanDataLen += length;

		}  // END: private void AppendHHScanData(byte[] scanData)

		private BarCodeSymbology GetCodeIDNew(byte[] scanData)
		{
			int num = scanData[1];
			byte handHeldCodeId = this.hhCodeID;
			StringBuilder builder = new StringBuilder(3, 3);
			builder.Append((char)scanData[2]);
			builder.Append((char)scanData[3]);
			builder.Append((char)scanData[4]);
			string str = builder.ToString();
			switch (handHeldCodeId)
			{
				case 0x61:
					return BarCodeSymbology.Codabar;

				case 0x62:
					return BarCodeSymbology.Code39;

				case 0x69:
					return BarCodeSymbology.Code93;

				case 0x6a:
					return BarCodeSymbology.Code128;

				case 100:
					if (str == "]E3" || (String.IsNullOrEmpty(str) && num > 13))
					{
						return BarCodeSymbology.Ean13S;
					}
					return BarCodeSymbology.EanJan13;

				case 0x44:
					if (str == "]E3" || (String.IsNullOrEmpty(str) && num > 8))
					{
						return BarCodeSymbology.Ean8S;
					}
					return BarCodeSymbology.EanJan8;

				case 0x66:
					return BarCodeSymbology.TF;

				case 0x65:
					return BarCodeSymbology.Itf;

				case 120:
					return BarCodeSymbology.Maxicode;

				case 0x79:
					return BarCodeSymbology.Gs1DataBar;

				case 0x4f:
					if (str != "]o1" && str == "]o2")
					{
						return BarCodeSymbology.Ocrb;
					}
					return BarCodeSymbology.Ocra;

				case 0x72:
					return BarCodeSymbology.Pdf417;

				case 0x63:
					if (str == "]E3" || (String.IsNullOrEmpty(str) && num > 13))
					{
						return BarCodeSymbology.Upcas;
					}
					return BarCodeSymbology.Upca;

				case 0x49:
					return BarCodeSymbology.Ean128;

				case 0x45:
					if (str == "]E3" || (String.IsNullOrEmpty(str) && num > 13))
					{
						return BarCodeSymbology.Upces;
					}
					return BarCodeSymbology.Upce;
			}
			return BarCodeSymbology.Other;

		}  // END: private BarCodeSymbology GetCodeIDNew(byte[] scanData)

		private BarCodeSymbology GetCodeIDOld(byte[] scanData)
		{
			int num = scanData[1];
			switch (this.hhCodeID)
			{
				case 0x61:
					return BarCodeSymbology.Codabar;

				case 0x62:
					return BarCodeSymbology.Code39;

				case 0x69:
					return BarCodeSymbology.Code93;

				case 0x6a:
					return BarCodeSymbology.Code128;

				case 100:
					switch (num)
					{
						case 8:
						case 10:
							return BarCodeSymbology.EanJan8;
					}
					return BarCodeSymbology.EanJan13;

				case 0x65:
					return BarCodeSymbology.Itf;

				case 120:
					return BarCodeSymbology.Maxicode;

				case 0x79:
					return BarCodeSymbology.Gs1DataBar;

				case 0x6f:
					return BarCodeSymbology.Ocra;

				case 0x72:
					return BarCodeSymbology.Pdf417;

				case 0x63:
					switch (num)
					{
						case 8:
						case 10:
						case 13:
							return BarCodeSymbology.Upce;
					}
					return BarCodeSymbology.Upca;
			}
			return BarCodeSymbology.Other;

		}  // END:  private BarCodeSymbology GetCodeIDOld(byte[] scanData)

		private byte[] GetHHScanData()
		{
			byte[] destinationArray = new byte[5 + this.hhScanDataLen];
			destinationArray[0] = 2;
			destinationArray[1] = (byte)this.hhScanDataLen;
			Array.Copy(this.hhAimID, 0, destinationArray, 2, 3);
			Array.Copy(this.hhScanData, 0, destinationArray, 5, this.hhScanDataLen);
			return destinationArray;

		}  // END: private byte[] GetHHScanData()

		private string getModelName(int pid)
		{
			if (this.isValidPID(pid))
			{
				return (string)this.scannerHash[pid];
			}
			return ("PID: " + pid + " is not recognized.");

		}  // END: private string getModelName(int pid)

		private BarCodeSymbology GetSymbology(byte[] scanData)
		{
			if (scanData[2] == 0x5d)
			{
				if (this.isMatrixScanner(this.ReadThread._Attributes.ProductID))
				{
					return this.GetCodeIDNew(scanData);
				}
				return this.GetCodeIDOld(scanData);
			}
			Logger.Info("HHScanner", "Invalid AIM Symbology: AIM Identifier_0 should be ']' ");
			return BarCodeSymbology.Unknown;

		}  // END: private BarCodeSymbology GetSymbology(byte[] scanData)

		private void initScannerHash()
		{
			this.scannerHash.Clear();
			this.scannerHash.Add(0x107, "IT3800-15");
			this.scannerHash.Add(0x127, "IT3800-14");
			this.scannerHash.Add(0x2e7, "3800G");
			this.scannerHash.Add(0x167, "IT5600");
			this.scannerHash.Add(0x187, "IT5800");
			this.scannerHash.Add(0x1c7, "IT4800");
			this.scannerHash.Add(0x1e7, "IT4010");
			this.scannerHash.Add(0x287, "IT4200");
			this.scannerHash.Add(0x207, "IT4600");
			this.scannerHash.Add(0x267, "IT5620");
			this.scannerHash.Add(0x227, "IT4800");

		}  // END: private void initScannerHash()

		private bool isMatrixScanner(int pid)
		{
			bool flag = true;
			if (!this.isValidPID(pid))
			{
				return flag;
			}
			switch (pid)
			{
				case 0x107:
				case 0x127:
					return false;
			}
			return true;

		}  // END: private bool isMatrixScanner(int pid)

		private bool isValidPID(int pid)
		{
			return this.scannerHash.ContainsKey(pid);

		}  // END: private bool isValidPID(int pid)

		private void ResetHHDataItems()
		{
			Array.Clear(this.hhAimID, 0, 3);
			this.hhScanDataLen = 0;
			Array.Clear(this.hhScanData, 0, this.hhScanData.Length);

		}  // END: private void ResetHHDataItems()

		private void SetDeviceStatistics()
		{
			base.SetStatisticValue("ManufacturerName", "Hand Held Products Inc.");
			base.SetStatisticValue("ManufactureDate", "September 19, 2006");
			base.SetStatisticValue("ModelName", this.getModelName(this.ReadThread._Attributes.ProductID));
			base.SetStatisticValue("MechanicalRevision", "1.0");
			base.SetStatisticValue("Interface", "USB");

		}  // END: private void SetDeviceStatistics()

		#endregion

	}  // END: public class HandHeldScanner : ScannerBase
}  // END: CA.RetailBeerSystems.POSServiceObjects.Scanners